package com.xudm.cdg.service;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.xudm.cdg.config.MinioConfig;
import com.xudm.cdg.entity.ResponseResult;
import com.xudm.cdg.entity.cosmic.*;
import com.xudm.cdg.entity.enumerate.DataMoveTypeEnum;
import com.xudm.cdg.entity.system.FileGenerationRecord;
import com.xudm.cdg.interceptor.LoginUtil;
import com.xudm.cdg.listener.CosmicExcelModelDataListener;
import com.xudm.cdg.mapper.system.FileGenerationRecordMapper;
import com.xudm.cdg.utils.PlantumlUtil;
import com.xudm.cdg.utils.SequenceDescriptionUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CosmicDocumentgenerateService {
    public static final String OUTPUT_LOCAL = "D:\\DevelopSpace\\workspace\\COSMIC\\template\\output\\\\{}\\COSMIC文档生成-{}.docx";
    public static final String OUTPUT_MINIO = "generate/COSMIC文档生成-{}.docx";
    public static final String TEMPLATE_PATH = "D:\\DevelopSpace\\workspace\\COSMIC\\template\\word_template.docx";
    private final FeatureDescriptionService featureDescriptionService;
    private final MinioService minioService;
    private final MinioConfig minioConfig;
    private final DataDictService dataDictService;

    @Resource
    private FileGenerationRecordMapper fileGenerationRecordMapper;

    public CosmicDocumentgenerateService(FeatureDescriptionService featureDescriptionService, MinioService minioService, MinioConfig minioConfig, DataDictService dataDictService) {
        this.featureDescriptionService = featureDescriptionService;
        this.minioService = minioService;
        this.minioConfig = minioConfig;
        this.dataDictService = dataDictService;
    }

    /**
     * 生成cosmic文档
     *
     * @param file 文件
     * @throws IOException
     */
    public void readExcelAndWriterToLocal(MultipartFile file) throws IOException {
        // 生成cosmic文档
        InputStream fis = file.getInputStream();
        CosmicExcelModelDataListener listener = new CosmicExcelModelDataListener();
        log.info("开始读取Excel文件");
        EasyExcel.read(fis, CosmicExcelModel.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().headRowNumber(1).doRead();
        List<CosmicExcelModel> dataList = listener.getDataList();
        log.info("读取Excel文件完成");
        log.info("开始组装数据");
        Map<String, Object> dataMap = buildTemplateData(dataList);
        log.info("组装数据完成");
        log.info("开始生成文档");
        //把文件上传到minio  生成文件名
        //获取当前年月
        String year = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN).substring(0, 4);
        String month = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN).substring(4, 6);
        String outPutFilePath = StrUtil.format(OUTPUT_LOCAL, year + "-" + month, LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN));
        //如果文件夹不存在则创建
        File file1 = new File(outPutFilePath);
        File parentFile = file1.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        writeDataToTemplate(new FileOutputStream(outPutFilePath), dataMap);
        log.info("生成文档完成--{}", outPutFilePath);
    }



    /**
     * 生成cosmic文档并上传到minio
     *
     * @param file
     * @return
     */
    public ResponseResult<?> readExcelAndWriterToMinio(MultipartFile file) {
        String loginId = LoginUtil.getLoginId();
        Map<String, Object> res = new HashMap<>();
        try (InputStream fis = file.getInputStream()) {
            //先生成文档记录
            FileGenerationRecord fileGenerationRecord = new FileGenerationRecord();
            fileGenerationRecord.setOriginFileName(file.getOriginalFilename());
            fileGenerationRecord.setCreatedBy(loginId);
            fileGenerationRecord.setCreatedTime(LocalDateTime.now());
            fileGenerationRecord.setUpdatedBy(loginId);
            fileGenerationRecord.setUpdatedTime(LocalDateTime.now());
            fileGenerationRecord.setGenFlag(0);
            String fileName = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
            String filePath = StrUtil.format(OUTPUT_MINIO, fileName);
            String fullPath = StrUtil.format("{}/{}/{}", minioConfig.getEndpoint(), minioConfig.getBucketName(), filePath);
            fileGenerationRecord.setGenerateFileAddress(fullPath);
            fileGenerationRecord.insert();
            res.put("filePath", fullPath);
            //异步调用生成文档
            CompletableFuture.runAsync(() -> {
                // 生成cosmic文档
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                CosmicExcelModelDataListener listener = new CosmicExcelModelDataListener();
                log.info("开始读取Excel文件");
                EasyExcel.read(fis, CosmicExcelModel.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().headRowNumber(1).doRead();
                List<CosmicExcelModel> dataList = listener.getDataList();
                log.info("读取Excel文件完成");
                log.info("开始组装数据");
                Map<String, Object> dataMap = buildTemplateData(dataList);
                log.info("组装数据完成");
                log.info("开始生成文档");

                try {
                    writeDataToTemplate(outputStream, dataMap);
                } catch (IOException e) {
                    log.error("生成文档失败", e);
                    fileGenerationRecord.setGenFlag(2);
                    fileGenerationRecord.updateById();
                    throw new RuntimeException(e);
                }
                //把文件上传到minio  生成文件名
                minioService.uploadFile(filePath, new ByteArrayInputStream(outputStream.toByteArray()));
                fileGenerationRecord.setGenFlag(1);
                fileGenerationRecord.setUpdatedBy(loginId);
                fileGenerationRecord.setUpdatedTime(LocalDateTime.now());
                fileGenerationRecord.updateById();
                log.info("生成文档完成--{}", filePath);
            });
            return ResponseResult.success(res);
        } catch (Exception e) {
            log.error("生成文档失败", e);
            return ResponseResult.failed("生成文档失败");
        }
    }

    /**
     * 构建模版数据
     *
     * @param dataList 数据列表
     * @return
     */
    private Map<String, Object> buildTemplateData(List<CosmicExcelModel> dataList) {
        // 从CosmicExcelModel对象列表中提取第一层级的数据 然后创建相应的数据列表用于存储下一层级的数据
        Map<String, List<CosmicExcelModel>> collect1 = dataList.stream().collect(Collectors.groupingBy(CosmicExcelModel::getModelName));
        List<Map<String, Object>> dataList1 = new ArrayList<>();
        collect1.forEach((k1, v1) -> {
            // 从第一层级的数据中提取第二层级的数据
            // 然后创建相应的数据列表用于存储下一层级的数据
            List<Map<String, Object>> dataList2 = new ArrayList<>();
            Map<String, Object> dataMap1 = new HashMap<>();
            dataMap1.put("title1", k1);
            dataMap1.put("dataList2", dataList2);
            dataList1.add(dataMap1);
            Map<String, List<CosmicExcelModel>> collect2 = v1.stream().collect(Collectors.groupingBy(CosmicExcelModel::getCustomerDemand));
            collect2.forEach((k2, v2) -> {
                // 从第二层级的数据中提取第三层级的数据
                // 然后创建相应的数据列表用于存储下一层级的数据
                List<Map<String, Object>> dataList3 = new ArrayList<>();
                Map<String, Object> dataMap2 = new HashMap<>();
                dataMap2.put("title2", k2);
                dataMap2.put("dataList3", dataList3);
                dataList2.add(dataMap2);
                Map<String, List<CosmicExcelModel>> collect3 = v2.stream().collect(Collectors.groupingBy(CosmicExcelModel::getFunctionalUserDemand));
                collect3.forEach((k3, v3) -> {
                    List<Map<String, Object>> dataList4 = new ArrayList<>();
                    Map<String, Object> dataMap3 = new HashMap<>();
                    dataMap3.put("title3", k3);
                    dataMap3.put("dataList4", dataList4);
                    dataList3.add(dataMap3);
                    // 从第三层级的数据中提取第四层级的数据
                    v3.stream().collect(Collectors.groupingBy(CosmicExcelModel::getFunctionalProcessing)).forEach((k4, v4) -> {
                        CosmicExcelModel cosmicExcelModelStart = v4.get(0);
                        Map<String, Object> dataMap4 = new HashMap<>();
                        dataMap4.put("title4", k4);
                        //构建详细数据
                        //1、 功能详细描述
                        //调用文心一言大模型生成描述
                        String collect = v4.stream().map(CosmicExcelModel::getDataAttribute).collect(Collectors.joining(", "));
                        String question = "请写一段关于“" + cosmicExcelModelStart.getFunctionalProcessing() + "”的软件功能描述，大于60字，数据内容如下：“" + collect + "”";
                        String featureDescription = featureDescriptionService.getFeatureDescription(question);
                        dataMap4.put("featureDescription", featureDescription);
                        //2、功能界面原型
                        //dataMap4.put("featureInput", cosmicExcelModelStart.getFunctionalInput());
                        //3、用户交互内容
                        List<UserInteractiveContent> uicList = new ArrayList<>();
                        List<CosmicExcelModel> cosmicExcelModelList = v4.stream().filter(cosmicExcelModel -> cosmicExcelModel.getDataMovementType().equalsIgnoreCase("E")).collect(Collectors.toList());
                        for (int i = 0; i < cosmicExcelModelList.size(); i++) {
                            CosmicExcelModel cosmicExcelModel = cosmicExcelModelList.get(i);
                            UserInteractiveContent uic = new UserInteractiveContent();
                            uic.setNumber((i + 1) + "");
                            uic.setDesignation(cosmicExcelModel.getSubFunctionalProcessing());
                            uic.setType("请求");
                            uic.setDescription(cosmicExcelModel.getTriggerEvent());
                            uicList.add(uic);
                        }
                        dataMap4.put("uicList", uicList);

                        //4、用户交互功能
                        List<UserInteractionFunction> uifList = new ArrayList<>();
                        for (int i = 0; i < v4.size(); i++) {
                            CosmicExcelModel cosmicExcelModel = v4.get(i);
                            UserInteractionFunction uic = new UserInteractionFunction();
                            uic.setNumber((i + 1) + "");
                            uic.setDesignation(cosmicExcelModel.getSubFunctionalProcessing());
                            String type = DataMoveTypeEnum.valueOf(cosmicExcelModel.getDataMovementType().toUpperCase()).getValue();
                            uic.setType(type);
                            uic.setDescription(cosmicExcelModel.getTriggerEvent());
                            uifList.add(uic);
                        }
                        dataMap4.put("uifList", uifList);

                        //5、功能交互流程
                        // 提取发起者
                        String initiator = SequenceDescriptionUtil.extractInitiator(cosmicExcelModelStart.getFunctionalUser());
                        dataMap4.put("initiator", StrUtil.isNotBlank(initiator) ? initiator.replace("\n", "") : "");
                        // 提取接收者
                        String receiver = SequenceDescriptionUtil.extractReceiver(cosmicExcelModelStart.getFunctionalUser());
                        dataMap4.put("receiver", StrUtil.isNotBlank(receiver) ? receiver.replace("\n", "") : "");
                        // 提取触发事件
                        String triggerEvent = cosmicExcelModelStart.getTriggerEvent();
                        dataMap4.put("triggerEvent", triggerEvent);
                        // 构建时序图
                        Object[] objects = PlantumlUtil.buildUmlSourceAndDescription(v4);
                        String unlSource = (String) objects[0];
                        List<SequenceDescription> descriptions = (List<SequenceDescription>) objects[1];
                        String sequenceDescription = SequenceDescriptionUtil.getSequenceDescription(descriptions);
                        InputStream inputStream = PlantumlUtil.getInputStream(unlSource);
                        // 插入时序图
                        dataMap4.put("timeSequenceDiagram", Pictures.ofStream(inputStream, PictureType.PNG).create());
                        // 插入时序图描述
                        dataMap4.put("sequenceDescription", sequenceDescription);

                        //6、数据字典设计
                        List<Map<String, Object>> dictJsonLoopList = new ArrayList<>();
                        List<Map<String, Object>> dictTableLoopList = new ArrayList<>();
                        for (int i = 0; i < v4.size(); i++) {
                            CosmicExcelModel cosmicExcelModel = v4.get(i);
                            String dataMovementType = cosmicExcelModel.getDataMovementType();
                            String dataAttribute = cosmicExcelModel.getDataAttribute();
                            String dataGroup = cosmicExcelModel.getDataGroup();
                            String subFunctionalProcessing = cosmicExcelModel.getSubFunctionalProcessing();
                            Map<String, Object> loopMap = new HashMap<>();
                            //如果是e和x则是json数据
                            if ("E".equalsIgnoreCase(dataMovementType) || "X".equalsIgnoreCase(dataMovementType)) {
                                loopMap.put("dataGroup", dataGroup);
                                loopMap.put("dictDescription", subFunctionalProcessing);
                                //String dictQuestion = "请把“" + dataAttribute + "”翻译成变量并给出合适的案例值然后组装成json,json组装以翻译后的变量名为key，案例数据为value。注意事项：json对象只能一层键值对的形式，不要嵌套且不能包含注释；变量需要符合标识符命名规则，不能包含中文，多个英文使用下划线分割或者使用小驼峰命名；案例值不能为对象。输出案例：```json\n{\n  \"reportFlowFormComponentAssociationSettingsUrl\": \"http://example.com/reportFlowSettings\",\n  \"componentId\": \"C001\"\n}\n``` ";
                                InputStream dataDictJsonImg = dataDictService.getDataDictJsonImg(dataAttribute);
                                loopMap.put("jsonPicture", Pictures.ofStream(dataDictJsonImg, PictureType.PNG).create());
                                dictJsonLoopList.add(loopMap);
                            } else {
                                loopMap.put("dataGroup", dataGroup);
                                loopMap.put("dictDescription", subFunctionalProcessing);
//                                String dictQuestion = "请把“" + dataAttribute + "”转成符合mysql数据库的字段，以0或者1表示非空，并以markdown表格的形式输出，表头为字段名、别名、类型、长度、非空，只返回marketdown格式的表格，不需要多余的描述";
                                List<DataDict> dictList = dataDictService.getDictList(dataAttribute);
                                loopMap.put("dictList", dictList);
                                dictTableLoopList.add(loopMap);
                            }
                        }
                        dataMap4.put("dictJsonLoopList", dictJsonLoopList);
                        dataMap4.put("dictTableLoopList", dictTableLoopList);
                        dataList4.add(dataMap4);
                    });
                });
            });
        });

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("dataList1", dataList1);
        return dataMap;
    }

    /**
     * 生成cosmic文档
     *
     * @param outputStream 输出流
     * @param dataMap      数据
     * @throws IOException
     */
    private void writeDataToTemplate(OutputStream outputStream, Map<String, Object> dataMap) throws IOException {
        //表格行循环
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure config = Configure.builder().useSpringEL(true)
                .bind("uicList", policy).bind("uifList", policy).bind("dictList", policy).build();
        XWPFTemplate template = XWPFTemplate.compile(TEMPLATE_PATH, config).render(dataMap);
        template.writeAndClose(outputStream);
    }
}
